#include "mqttFunc.h"
//
#include "acl_cpp/stdlib/string.hpp"
#include "acl_cpp/stdlib/json.hpp"

//
#include <time.h>
#include <sys/timeb.h>
#ifdef __linux__
#include <stdexcept>
#include <sys/time.h>
#endif
//
#include "Log.h"
//
#include "business_def.h"
#include "verifyforcontrolcache.h"
//
//c++ version
#include "HMAC_SHA1.h"
#include "Base64.h"
//c version
#include "HMACSHA1.h"
//
#include "strchange.h"
#include "pfunc.h"



MQTTFUNC::MQTTFUNC()
	: ptr_bdef(BusinessDef::getInstance())
	, queueforwrite_mqtt(QueueDataSingle<SocketMqttWriteItem>::getInstance())
	, to_gather_queue(QueueDataSingle<DataToGather>::getInstance())
	, is_Verification(false)
	, ptr_vcc(VerifyForControlCache::getInstance())
{
	pyfree::AreaInfo ainfo = ptr_bdef->getAreaInfo();
	m_AreaInfo.areaid = ainfo.areaId;
	char buf[64] = { 0 };
	sprintf(buf, "%ld", m_AreaInfo.areaid);
	m_AreaInfo.areaId = std::string(buf);
	sprintf(buf, "%d", ainfo.areaType);
	m_AreaInfo.areaType = std::string(buf);
	m_AreaInfo.areaName = ainfo.areaName;
	m_AreaInfo.areaDesc = ainfo.areaDesc;
	m_AreaInfo.areaDesc = pyfree::ASCII2UTF_8(m_AreaInfo.areaDesc);
	//
	pyfree::MqttConf conf_ = ptr_bdef->getMqttConf();
	ControlCheckFunc = conf_.hmac_sha_func;
	ControlCheckKey = conf_.hmac_sha_key;
	is_Verification = ptr_bdef->getVerificationFunc();
};

MQTTFUNC::~MQTTFUNC()
{

};
//
void MQTTFUNC::InitDevsForSend(std::queue<std::string> &bufs)
{
	std::vector<Dev> devs_;
	if (ptr_bdef->getDevs(devs_, true))
	{
		acl::json json;
		acl::json_node& root = json.get_root();
		acl::json_node *node0, *node1, *node2, *node3, *node4, *node5, *node6, *node7, *node8, *node9, *node10, *node11;
		node0 = &root;

		node1 = &json.create_node("area_sn", m_AreaInfo.areaId.c_str());
		node0->add_child(node1);
		node1 = &json.create_node("area_name", m_AreaInfo.areaName.c_str());
		node0->add_child(node1);
		node1 = &json.create_node("area_type", m_AreaInfo.areaType.c_str());
		node0->add_child(node1);
		node1 = &json.create_node("area_desc", m_AreaInfo.areaDesc.c_str());
		node0->add_child(node1);
		//
		node1 = &json.create_array();
		node2 = &json.create_node("device", node1);
		node0->add_child(node2);
		//

		for (std::vector<Dev>::iterator itdev = devs_.begin(); itdev != devs_.end(); ++itdev)
		{
			char buf[64] = { 0 };
			sprintf(buf, "%llu", itdev->devInfo.devID);
			node5 = &json.create_node("dev_sn", buf);
			node6 = &json.create_node("dev_name", itdev->devInfo.name.c_str());
			sprintf(buf, "%d", itdev->devInfo.devType);
			node7 = &json.create_node("dev_type", buf);
			node8 = &json.create_node("dev_desc", ASCII2UTF_8(itdev->devInfo.desc).c_str());

			node4 = &json.create_array();
			node3 = &json.create_node().add_child(node5).add_child(node6).add_child(node7).add_child(node8)
				.add_child(json.create_node("point", node4));
			node1->add_child(node3);
			for (std::map<unsigned int, PInfo>::iterator itp = itdev->pInfo.begin(); itp != itdev->pInfo.end(); ++itp)
			{
				sprintf(buf, "%ud", itp->second.pID);
				node5 = &json.create_node("point_sn", buf);
				sprintf(buf, "%d", static_cast<int>(itp->second.pType));
				node6 = &json.create_node("point_type", buf);
				node7 = &json.create_node("point_name", itp->second.name.c_str());
				node8 = &json.create_node("point_desc", ASCII2UTF_8(itp->second.desc).c_str());

				node9 = &json.create_node("time", pyfree::getDateTime(static_cast<int>(time(NULL)), 0).c_str());
				sprintf(buf, "%.02f", itp->second.defVal);
				node10 = &json.create_node("value", buf);
				node11 = &json.create_node()
					.add_child(node5)
					.add_child(node6)
					.add_child(node7)
					.add_child(node8)
					.add_child(node9)
					.add_child(node10);
				node4->add_child(node11);
			}
			acl::string aclbuf;
			try {
				json.build_json(aclbuf);
#ifdef _DEBUG
				printf(UTF_82ASCII(std::string(aclbuf)).c_str());
				printf("\n");
#endif
			}
			catch (...)
			{
				CLogger::createInstance()->Log(MsgError,
					"MySocketWD Run for init data writing and json.build_json Exception"
					",[%s %s %d]!"
					, __FILE__, __FUNCTION__, __LINE__);
				node1->clear();
				continue;
			}
			if (aclbuf[aclbuf.length() - 1] == '\n')
			{
				aclbuf += "\r";
			}
			else
			{
				aclbuf += "\n\r";
			}
			std::string bufData = std::string((char*)aclbuf.c_str(), static_cast<int>(aclbuf.length()));
			bufs.push(bufData);
			node1->clear();
		}
	}
}

bool MQTTFUNC::getCacheInfos(std::map<unsigned long long, std::queue<JsonPValue> > &its, int sizel)
{
	int rsize = queueforwrite_mqtt->size();
	if (rsize <= 0)
	{
		return false;
	}
	rsize = rsize<sizel ? rsize : sizel;
	SocketMqttWriteItem it;
	for(int i=0;i<rsize;++i){
		if(queueforwrite_mqtt->pop(it))
		{
			std::map<unsigned long long, std::queue<JsonPValue> >::iterator itpos = its.find(it.devID);
			if (itpos != its.end()) 
			{
				JsonPValue jval;
				jval.pID = it.pID;
				jval.ptype = it.ptype;
				jval.sec = it.evtTimeS;
				jval.msec = it.evtTimeMS;
				jval.val = it.val;
				//jval.taskID = it.taskID;
				its[it.devID].push(jval);
			}
			else {
				std::queue<JsonPValue> pids;
				JsonPValue jval;
				jval.pID = it.pID;
				jval.ptype = it.ptype;
				jval.sec = it.evtTimeS;
				jval.msec = it.evtTimeMS;
				jval.val = it.val;
				//jval.taskID = it.taskID;
				pids.push(jval);
				its[it.devID] = pids;
			}
		}else{
			break;
		}
	}
	return !its.empty();
}

void MQTTFUNC::getPValueJsonDesc(std::string &jsonDec)
{
	std::map<unsigned long long, std::queue<JsonPValue> > its;
	if (this->getCacheInfos(its, 5))
	{
		acl::json json;
		acl::json_node& root = json.get_root();
		acl::json_node *node0, *node1, *node2, *node3, *node4, *node5, *node6, *node7, *node8;
		node0 = &root;

		node1 = &json.create_node("area_sn", m_AreaInfo.areaId.c_str());
		node0->add_child(node1);
		//
		node1 = &json.create_array();
		node2 = &json.create_node("device", node1);
		node0->add_child(node2);

		for (std::map<unsigned long long, std::queue<JsonPValue> >::iterator itdev = its.begin();
			itdev != its.end(); ++itdev)
		{
			char buf[64] = { 0 };
			sprintf(buf, "%llu", itdev->first);

			node4 = &json.create_array();
			node3 = &json.create_node().add_child(json.create_node("dev_sn", buf))
				.add_child(json.create_node("point", node4));
			node1->add_child(node3);

			while (!itdev->second.empty())
			{
				JsonPValue jval = itdev->second.front();
				sprintf(buf, "%ud", jval.pID);
				node5 = &json.create_node("point_sn", buf);
				node6 = &json.create_node("time", pyfree::getDateTime(jval.sec, jval.msec).c_str());
				sprintf(buf, "%.02f", jval.val);
				node7 = &json.create_node("value", buf);
				node8 = &json.create_node().add_child(node5).add_child(node6).add_child(node7);
				node4->add_child(node8);

				itdev->second.pop();
			}
		}

		acl::string aclbuf;
		try {
			json.build_json(aclbuf);
		}
		catch (...)
		{
			CLogger::createInstance()->Log(MsgError,
				"JsonSocketWD for send data writing and json.build_json Exception"
				",[%s %s %d]!"
				, __FILE__, __FUNCTION__, __LINE__);
			return;
		}
		if (aclbuf[aclbuf.length() - 1] == '\n')
		{
			aclbuf += "\r";
		}
		else
		{
			aclbuf += "\n\r";
		}
		jsonDec = std::string((const char*)aclbuf.c_str(), static_cast<int>(aclbuf.length()));
	}
}

//JSon To MyRecStructForXFControl
int MQTTFUNC::AddFrame(const char *buf, int len, ControlFromMqtt &mrsfc)
{
	acl::json json;
	try {
		json.update(buf);
	}
	catch (...)
	{
		CLogger::createInstance()->Log(MsgWarn,
			"ConsumerToDevSrv::AddFrame for json.update error"
			",please make sure the[%s,%d] is right,[%s %s %d]!"
			, buf, len
			, __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}
	acl::string aclbuf;
	try {
		json.build_json(aclbuf);
		CLogger::createInstance()->Log(MsgInfo
			, "ConsumerToDevSrv::AddFrame Received:%s", aclbuf.c_str());
	}
	catch (...)
	{
		CLogger::createInstance()->Log(MsgError,
			"ConsumerToDevSrv Run for init data writing and json.build_json Exception"
			",[%s %s %d]!"
			, __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}
	//acl::string aclbuf;
	//json.build_json(aclbuf);
	//Print_NOTICE("Received AddFrame:%s\r\n", aclbuf.c_str());

	acl::json_node* iter = json.first_node();
	while (iter)
	{
		if (iter->tag_name())
		{
			if (0 == strcmp("area_sn", iter->tag_name()))
			{
				mrsfc.areaID_ = atol(iter->get_text());
				mrsfc.valCount += 1;
			}
			else if (0 == strcmp("dev_sn", iter->tag_name()))
			{
				mrsfc.devID = atol(iter->get_text());
				mrsfc.valCount += 1;
			}
			else if (0 == strcmp("point_sn", iter->tag_name()))
			{
				mrsfc.pID = atol(iter->get_text());
				mrsfc.valCount += 1;
			}
			else if (0 == strcmp("value", iter->tag_name()))
			{
				mrsfc.val = static_cast<float>(atof(iter->get_text()));
				mrsfc.valCount += 1;
			}
			else if (0 == strcmp("code", iter->tag_name()))
			{
				mrsfc.code = iter->get_text();
				mrsfc.valCount += 1;
			}
			else
			{
				Print_NOTICE("tag: %s, value: %s\r\n", iter->tag_name(), iter->get_text());
			}
		}
		iter = json.next_node();
	}

	return 1;
};

bool MQTTFUNC::CheckFrame(ControlFromMqtt mrsfc)
{
	if (ControlCheckFunc)
	{
		if (5 != mrsfc.valCount)
		{
			return false;
		}
		//
		if (!checkCode(mrsfc))
		{
			return false;
		}
	}
	//iter = NULL;
	if (4 == mrsfc.valCount || 5 == mrsfc.valCount)
	{
		if (!createControlCmd(mrsfc))
		{
			return false;
		}
	}
	return true;
};

std::string MQTTFUNC::hmac_sha_code(std::string key_,std::string temp_)
{
	char hmac_buf[256] = { 0 };
	#ifdef WIN32
	hmac_sha((char*)key_.c_str(), static_cast<int>(key_.length()) + 1
		, (char*)temp_.c_str(), static_cast<int>(temp_.length()), hmac_buf, 20);
	#else
	CHMAC_SHA1 sha1;
	sha1.HMAC_SHA1((unsigned char*)temp_.c_str()
		, static_cast<int>(temp_.length())
		, (unsigned char*)key_.c_str()
		, static_cast<int>(key_.length())
		, (unsigned char*)hmac_buf);
	#endif
	std::string hmac = std::string(hmac_buf, strlen(hmac_buf));
	return hmac;
}

bool MQTTFUNC::checkCode(ControlFromMqtt mrsfc)
{
	char bufComment[256] = { 0 };
	sprintf(bufComment, "%d;%ld;%ld;%.2f", mrsfc.areaID_, mrsfc.devID, mrsfc.pID, mrsfc.val);
	std::string sortQueryStringTmp = std::string(bufComment);
	
	std::string key_ = ASCII2UTF_8(ControlCheckKey);
	std::string temp_ = ASCII2UTF_8(sortQueryStringTmp);
	//
	std::string hmac = hmac_sha_code(key_,temp_);
	hmac = pyfree::Encode((const unsigned char*)hmac.c_str(), static_cast<int>(hmac.length()));
	if (0 != strcmp(mrsfc.code.c_str(), hmac.c_str()))
	{
		CLogger::createInstance()->Log(MsgInfo, "rec hmac:%s is not map create hmac:%s"
			, mrsfc.code.c_str(), hmac.c_str());
		return false;
	}
	return true;
}

bool MQTTFUNC::createControlCmd(ControlFromMqtt mrsfc)
{
	if (m_AreaInfo.areaid != mrsfc.areaID_)
	{
		CLogger::createInstance()->Log(MsgInfo
			, "ConsumerToDevSrv::createControlCmd local_areaID[%d] is not map rec_areaID[%d]"
			, m_AreaInfo.areaid, mrsfc.areaID_);
		return false;
	}
	unsigned long taskID = pyfree::getTaskIDFromDateTime();
	PFrom _pfrom;
	if (ptr_bdef->getFromInfo(mrsfc.devID, static_cast<int>(mrsfc.pID), _pfrom))
	{
		float _val = mrsfc.val;
		ptr_bdef->getCValue(mrsfc.devID, static_cast<unsigned int>(mrsfc.pID), _val);
		DataToGather wd(_pfrom.ipLong, OnSet, _pfrom.pID, _pfrom.pType, _val, 0, "JSon_Control", taskID);
		to_gather_queue->add(wd);

		CLogger::createInstance()->Log(MsgInfo
			, "TaskID[%lu] and down_node[1] setPValue from Dev Server,time(%s)"
			",devID(%ld),pID(%ld),val(%.3f),"
			"down_control_map ip[%s],pID(%d),pType(%d),val(%.2f)"
			, taskID
			, pyfree::getCurrentTime().c_str()
			, mrsfc.devID, mrsfc.pID, mrsfc.val
			, _pfrom.ipStr.c_str()
			, _pfrom.pID, static_cast<int>(_pfrom.pType), _val);
		
		if (is_Verification) {
			VerificationCache vit;
			vit.execTime = pyfree::getCurrentTimeByFormat("%04d%02d%02dT%02d%02d%02dZ");
			vit.taskID = taskID;
			vit.taskDesc = "JSon_Control";
			vit.devID = static_cast<unsigned long>(mrsfc.devID);
			vit.devDesc = _pfrom.devDesc;
			vit.pID = static_cast<unsigned long>(mrsfc.pID);
			vit.pDesc = _pfrom.pDesc;
			vit.pType = static_cast<unsigned int>(_pfrom.pType);
			vit.val = mrsfc.val;
			vit.limitTimeForCheck = static_cast<unsigned int>(time(NULL)) + 5;
			vit.eway_ = _pfrom.eway;
			ptr_vcc->addVerifyData(vit);
		}
	}
	else {
		//virtual ponit control
		PValueRet pret(mrsfc.val);
		ptr_bdef->setHValue(mrsfc.devID, static_cast<unsigned int>(mrsfc.pID), pret,true);
		CLogger::createInstance()->Log(MsgInfo
			, "TaskID[%lu] and down_node[0] setPValue from Dev Server,time(%s)"
			",devID(%ld),pID(%ld),val(%.3f)"
			",ditect set value to virtual ponit control"
			, taskID, pyfree::getCurrentTime().c_str()
			, mrsfc.devID, mrsfc.pID, pret.val_actual);
	}
	return true;
};

